﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;

namespace EcoSystem
{
    /// <summary>
    /// HTTP口调用请求提供给Script引擎的封装类
    /// </summary>
    public class ApiScriptService : ApplicationService, IApiScriptService
    {
        private readonly IHttpClientFactory HttpClientFactory;
        private readonly IHttpContextAccessor HttpContextAccessor;

        public ApiScriptService(
            IHttpClientFactory httpClientFactory,
            IHttpContextAccessor httpContextAccessor = null)
        {
            HttpClientFactory = httpClientFactory;
            HttpContextAccessor = httpContextAccessor;
        }

        public async Task<string> DeleteAsync(string url, string queryString = null, Dictionary<string, string> headers = null)
        {
            var request = new HttpRequestMessage(HttpMethod.Delete, url);
            var joinChar = (url.IndexOf("?") != -1) ? "&" : "?";
            request.RequestUri = new Uri(url + joinChar + queryString);
            var token = await GetTokenAsync();
            if (!string.IsNullOrWhiteSpace(token))
            {
                request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
            }
            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            return await RequestAsync(request);

        }

        public async Task<TResult> DeleteAsync<TResult>(string url, string queryString = null, Dictionary<string, string> headers = null)
        {
            var request = new HttpRequestMessage(HttpMethod.Delete, url);
            var joinChar = (url.IndexOf("?") != -1) ? "&" : "?";
            request.RequestUri = new Uri(url + joinChar + queryString);
            var token = await GetTokenAsync();
            if (!string.IsNullOrWhiteSpace(token))
            {
                request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
            }
            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            return await RequestAsync<TResult>(request);
        }

        public async Task<string> GetAsync(string url, string queryString = null, Dictionary<string, string> headers = null)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var joinChar = (url.IndexOf("?") != -1) ? "&" : "?";
            var token = await GetTokenAsync();
            if (!string.IsNullOrWhiteSpace(token))
            {
                request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
            }
            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            return await RequestAsync(request);
        }

        public async Task<TResult> GetAsync<TResult>(string url, string queryString = null, Dictionary<string, string> headers = null)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var joinChar = (url.IndexOf("?") != -1) ? "&" : "?";
            request.RequestUri = new Uri(url + joinChar + queryString);
            var token = await GetTokenAsync();
            if (!string.IsNullOrWhiteSpace(token))
            {
                request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
            }
            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            return await RequestAsync<TResult>(request);
        }

        public async Task<string> PostAsync(string url, string content, Dictionary<string, string> headers = null)
        {
            var request = new HttpRequestMessage(HttpMethod.Post, url);
            request.Content = new StringContent(content, Encoding.UTF8, "application/json");
            var token = await GetTokenAsync();
            if (!string.IsNullOrWhiteSpace(token))
            {
                request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
            }
            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            return await RequestAsync(request);
        }

        public async Task<TResult> PostAsync<TResult>(string url, string content, Dictionary<string, string> headers = null)
        {
            var request = new HttpRequestMessage(HttpMethod.Post, url);
            request.Content = new StringContent(content, Encoding.UTF8, "application/json");
            var token = await GetTokenAsync();
            if (!string.IsNullOrWhiteSpace(token))
            {
                request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
            }
            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            return await RequestAsync<TResult>(request);
        }

        public async Task<string> PutAsync(string url, string content, Dictionary<string, string> headers = null)
        {
            var request = new HttpRequestMessage(HttpMethod.Put, url);
            request.Content = new StringContent(content, Encoding.UTF8, "application/json");
            var token = await GetTokenAsync();
            if (!string.IsNullOrWhiteSpace(token))
            {
                request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
            }
            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            return await RequestAsync(request);
        }

        public async Task<TResult> PutAsync<TResult>(string url, string content, Dictionary<string, string> headers = null)
        {
            var request = new HttpRequestMessage(HttpMethod.Put, url);
            request.Content = new StringContent(content, Encoding.UTF8, "application/json");
            var token = await GetTokenAsync();
            if (!string.IsNullOrWhiteSpace(token))
            {
                request.Headers.Authorization = AuthenticationHeaderValue.Parse(token);
            }
            if (headers != null && headers.Count > 0)
            {
                foreach (var item in headers)
                {
                    request.Headers.Add(item.Key, item.Value);
                }
            }
            return await RequestAsync<TResult>(request);
        }



        private async Task<string> RequestAsync(HttpRequestMessage request)
        {
            var client = HttpClientFactory.CreateClient();
            var response = await client.SendAsync(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var content = await response.Content.ReadAsStringAsync();
                return content;
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.AppendLine("远程调用url:" + request.RequestUri.ToString());
                stringBuilder.AppendLine("返回状态:" + response.StatusCode.ToString());
                stringBuilder.AppendLine("返回内容:" + content);
                throw new UserFriendlyException("调用API接口出错!",
                    response.StatusCode.ToString(),
                    stringBuilder.ToString());
            }
        }
        private async Task<T> RequestAsync<T>(HttpRequestMessage request)
        {
            var client = HttpClientFactory.CreateClient();
            var response = await client.SendAsync(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var content = await response.Content.ReadAsStringAsync();
                if (string.IsNullOrEmpty(content)) { return default(T); }
                return JsonConvert.DeserializeObject<T>(content);
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.AppendLine("远程调用url:" + request.RequestUri.ToString());
                stringBuilder.AppendLine("返回状态:" + response.StatusCode.ToString());
                stringBuilder.AppendLine("返回内容:" + content);
                throw new UserFriendlyException(
                    "调用远程API数据源出错!",
                    response.StatusCode.ToString(),
                    stringBuilder.ToString());
            }
        }


        /// <summary>
        /// 获取当前用户的授权token
        /// </summary>
        /// <returns></returns>
        private async Task<string> GetTokenAsync()
        {
            HttpContextAccessor.HttpContext.Request.Headers.TryGetValue("Authorization", out var authorizationHeader);
            return await Task.FromResult(authorizationHeader);
        }
    }

    public class LoggerAppService : ApplicationService, ILoggerAppService
    {
        public void LogCritical(string message, params object[] args)
        {
            Logger.LogCritical(message, args);
        }

        public void LogDebug(string message, params object[] args)
        {
            Logger.LogDebug(message, args);
        }

        public void LogError(string message, params object[] args)
        {
            Logger.LogError(message, args);
        }

        public void LogInformation(string message, params object[] args)
        {
            Logger.LogInformation(message, args);
        }

        public void LogTrace(string message, params object[] args)
        {
            Logger.LogTrace(message, args);
        }

        public void LogWarning(string message, params object[] args)
        {
            Logger.LogWarning(message, args);
        }
    }
}
